import re
import os
class DebugStruct:
    address =0;
    line ="";
#
# Parse the asm file to find jal code in comment
#
class JalV2AsmParser:
    
    JAL = 1
    ASM = 2
    mode = JAL # can return JAL Code or ASM Code
    
    def __init__(self):
        self.varAdrMapping = {}
        self.adrVarMapping = {}
        
        # we need both relation as the same address can be mapped to several lines
        # i.e. "end if" hsn't it's own address
       
        self.lineToAdr = [0]*8192
        self.adrToLine = [0]*8192
        self.adr =[]       # private int[] adr = null;
        self.adressSet =[] # private Set adressSet = new HashSet();
        
        for i in range(0,8192):
            self.lineToAdr[i] = None
            self.adrToLine[i] = None
         
    def parseAsmFile(self,filename,noDebugList,debugList=()):
        
        self.varAdrMapping = {}
        self.adrVarMapping = {}
        self.addressMethodMapping = {}
        adresse = 0
        list = []
        meth = ""
        
        line = ""
        lineIndex= 0;
        orgFound = False
        file =""
        fin = None
        try:                           
            fin = open(filename,"r")   
            for line in fin:   
                #print ">>"+str(adresse)+" "+line.strip()
                if line.strip().upper() == "END" :
                    break
                # var mapping part
                if ("EQU" in line):
                    tmp = line.strip()
                    parts = re.split(r'\W+',tmp)
                    if (parts[2].startswith("0x")):
                        dec = int(parts[2],16)
                        # one addr can used by many var
                        if self.adrVarMapping.has_key(dec):
                            self.adrVarMapping[dec] = self.adrVarMapping[dec]+", "+parts[0]
                        else:
                            self.adrVarMapping[dec] = parts[0]
                        #one var belong in one adr (or at least starts at one address...)
                        self.varAdrMapping[parts[0]] = dec
                        
                # end var mapping

                if (line.startswith(";")):
                    try :
                        int(line[1:6].strip()); # to raise an execption for line that didnt strat with an adress
                        # JAL code
                        if (self.mode == JalV2AsmParser.JAL):
                            line = line.strip()
                            st = DebugStruct()
                            st.address = adresse
                            st.line = line[7:]
                            
                            #print str(st.address)+" "+ st.line
                            
                            if st.line.upper().startswith("PROCEDURE ") or st.line.upper().startswith("FUNCTION "):
                                meth = re.split(r"\W+", st.line)[1]
                            if st.line.upper().startswith("END PROCEDURE") or st.line.upper().startswith("END FUNCTION"):
                                self.addressMethodMapping[st.address] = meth 
                                meth = ""
                            if meth != "":
                               self.addressMethodMapping[st.address] = meth   
                            
                            if (file != ""): # show file that contains the code
                                libFile = os.path.basename(file).replace(".jal","")
                                st2 = DebugStruct()
                                st2.address = " "
                                st2.line = "-- "+file[2:]
                                
                                if (libFile.upper() in noDebugList) or (
                                    ("*" in noDebugList) 
                                    and libFile != os.path.basename(filename).replace(".asm","") 
                                    and "~"+libFile != os.path.basename(filename).replace(".asm","") 
                                    and libFile.upper() not in debugList):
                                        st2.line+=" [ignored]"
                                list.append(st2)
                                
                                file =""
                                lineIndex += 1
                            if (libFile.upper() not in noDebugList) :
                                if (
                                    ("*" not in noDebugList) 
                                    or libFile == os.path.basename(filename).replace(".asm","")
                                    or "~"+libFile == os.path.basename(filename).replace(".asm","")
                                    or libFile.upper() in debugList):
                                    
                                    if (not line[7:].startswith("include")):
                                        list.append(st)
                                        self.lineToAdr[lineIndex] = adresse # used to place breakpoint for a line
                                        if self.adrToLine[adresse] == None:
                                            self.adrToLine[adresse] = lineIndex # used to find the line to highligh when debuging
                                        lineIndex += 1
                       
                    except :
                        
                        file = line.strip() # file module
                        if ("command line:" in file):
                            file =""
                        
                # ASM code
                # with the -d option of jalv2, some line starting with space
                # may juste content comment and not asm code...
                parts = line.split(";")
                if (parts[0].startswith(" ")) and parts[0].strip()!="":
                    if (orgFound):
                        if (self.mode == JalV2AsmParser.ASM):
                            line = line.rstrip()
                            st = DebugStruct()
                            st.address = adresse
                            st.line = line[7:]
                            list.append(st)
                            self.lineToAdr[lineIndex] = adresse # used to place breakpoint for a line
                            self.adrToLine[adresse] = lineIndex # used to find the line to highligh when debuging
                            lineIndex = lineIndex + 1
                        
                        # TODO : macro can contains more then one line...
                        if not (line.strip().startswith("org ")): # org is a directive...
                             adresse = adresse + 1
                        else :
                            adresse = int(line.strip("org "))
                           
                    else:
                        if (line.strip().startswith("org ")):
                            orgFound = True
        except IOError, e:               
            print "Error in file IO: ", e 
        if fin: fin.close()              
        return list;
    @staticmethod
    def buildVarTypeDict(lines):
        array = {}
        arrayCpt = {}
        for st in lines:
            # st is a DebugStruct
            lg = st.line
            if lg.upper().strip().startswith("VAR "):
                parts = re.split(r'\s+',lg.strip())
                
                type = parts[1]
                name = parts[2]
                if type.upper() == "VOLATILE":
                    type = parts[2]
                    name = parts[3]
                if arrayCpt.has_key(name):
                    arrayCpt[name] += 1
                    name = "__"+name+"_%d" % arrayCpt[name]
                else:
                    arrayCpt[name] = 1    
                name = name.lower()
                
                array[name] = type
        return array